<?php

namespace App\Modules\Good;

use App\Exceptions\StandardException;
use App\Library\Lock;
use App\Library\OSS;
use App\Modules\Coupon\Models\Coupon;
use App\Modules\Coupon\Models\UserCoupon;
use App\Modules\Good\Models\Good;
use App\Modules\Good\Models\GoodSpec;
use App\Modules\Good\Models\UserBuyLimitRecord;
use App\Modules\Order\Models\CombinedOrder;
use App\Modules\Order\Models\Order;
use App\Modules\User\Models\User;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use App\Modules\Coupon\Manager as CouponManager;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Overtrue\LaravelWeChat\Facade as EasyWeChat;
use Ramsey\Uuid\Uuid;

class Manager
{
    public static function AttrValueToSpec($array1, $array2)
    {
        $re = [];
        foreach ($array1 as $value) {
            foreach ($array2 as $key => $value2) {

                $re[] = $value + [$key => $value2];
            }
        }
        return $re;
    }

    public static function updateShoppingCart(User $user, $data)
    {
        Redis::set("shopping:cart:{$user->id}", json_encode($data, true));
    }

    public static function getShoppingCart(User $user)
    {
        $data = Redis::get("shopping:cart:{$user->id}");
        if (!is_null($data)) {
            $data = json_decode($data, true);
        }
        return $data;
    }

    /**
     * @param $user
     * @param $shopId
     * @param $spec
     * @param $referrerId
     * @param null $couponId
     * @param array $param
     * @return CombinedOrder
     * @throws \Throwable
     */
    public static function createOrder($user, $spec, $referrerId, $couponId = null, $param = [], $balanceParam = [])
    {
        
        return Lock::lock("order:{$user->id}", 2, function () use ($user, $spec, $referrerId, $couponId, $param, $balanceParam) {
            $referrer = User::query()->find($referrerId);
            $orders = [];
            $isPrepay = $param['is_prepay'] ?? 0;

            DB::beginTransaction();
            $payNo = Order::getPayNo();
            foreach ($spec as $shopId => $tmp) {
                $price = 0;
                $originalPrice = 0;
                $number = [];
                $specIds = [];
                foreach ($tmp as $value) {
                    $specIds[] = $value['id'];
                    $number[$value['id']] = $value['number'];
                }
                $goodsPrice = [];
                $goodSpec = GoodSpec::query()
                    ->whereIn('id', $specIds)
                    ->get()
                    ->map(function (GoodSpec $item) use (&$price, &$originalPrice, $number, $isPrepay, &$goodsPrice) {
                        $price += ($isPrepay ? $item->prepay_price : $item->price) * $number[$item->id];
                        $originalPrice += $item->price * $number[$item->id];
                        $item->decrement('stock');
                        if ($item->stock < 0) {
                            throw new StandardException('库存不足');
                        }
                        if (isset($goodsPrice[$item->good_id])) {
                            $goodsPrice[$item->good_id] += $item->price * $number[$item->id];
                        } else {
                            $goodsPrice[$item->good_id] = $item->price * $number[$item->id];
                        }

                        return [
                            'id' => $item->id,
                            'good_id' => $item->good_id,
                            'price' => $item->price,
                            'prepay_price' => $item->prepay_price,
                            'discount_type' => $item->discount_type,
                            'discount_limit' => $item->discount_limit,
                            'discount_amount' => $item->discount_amount,
                            'param' => $item->param,
                            'number' => $number[$item->id],
                        ];
                    })
                    ->keyBy('id');
                $goods = Good::query()
                    ->where('shop_id', $shopId)
                    ->whereIn('id', $goodSpec->pluck('good_id')->all())
                    ->get()->keyBy('id');
                $buyLimitGoods = $goods->filter(function ($t) {
                    return $t->buy_limit > 0;
                });
                $buyRecord = UserBuyLimitRecord::query()
                    ->where('user_id', $user->id)
                    ->whereIn('goods_id', $buyLimitGoods->pluck('id')->all())
                    ->selectRaw('sum(number) as number, goods_id')
                    ->groupBy('goods_id')
                    ->get()
                    ->pluck('number', 'goods_id')
                    ->all();

                $goodSpec = $goodSpec->map(function ($item) use ($goods, &$rebate, $user, $number, $referrer, &$buyRecord) {
                    /** @var Good $tmp */
                    $tmp = $goods->get($item['good_id']);
                    if ($tmp->status == Good::STATUE_OFF) {
                        throw new StandardException("商品已下架");
                    }

                    if (isset($buyRecord[$item['good_id']])) {
                        $buyRecord[$item['good_id']] += $number[$item['id']];
                    } else {
                        $buyRecord[$item['good_id']] = $number[$item['id']];
                    }

                    if ($tmp['buy_limit'] > 0 && $tmp['buy_limit'] < $buyRecord[$item['good_id']]) {
                        throw new StandardException("超出限购数量");
                    }
                    $item['shop_id'] = $tmp['shop_id'];
                    $item['good_name'] = $tmp->name;
                    $item['buy_limit'] = $tmp->buy_limit;

                    $item['order_cover'] = OSS::instance()->getUrl($tmp->order_cover);
                    $item['is_free'] = $tmp->is_free;
                    $item['is_comment'] = 0;
                    return $item;
                });
                $personal = null;
                if (!is_null($referrer) && $referrer->level == 2) {
                    $personal = User::query()
                        ->where('level', '=', 3)
                        ->where('id', $referrer->personal_id)
                        ->first();
                }
                $discountAmount = 0;
                $gift = [];
                if (isset($param['has_discount'])) {

                    $goods->each(function (Good $item) use ($goodsPrice, &$discountAmount, &$gift) {
                        $discountAmount = $item->getDiscount($goodsPrice[$item->id]);
                        if ($discountAmount == 0) {
                            $discountAmount = $item->getFullReduction($goodsPrice[$item->id]);
                        }
                        $gift[] = $item->getGift();
                    });

                }

                //余额支付
                $is_balance  = !empty($balanceParam['is_balance'])  ? $balanceParam['is_balance']  : 0;
                $balance_pay = !empty($balanceParam['balance_pay']) ? $balanceParam['balance_pay'] : 0;
                // $price       = $is_balance == 1 ? ((($price - $balance_pay) < 0) ? 0 : ($price - $balance_pay)) : $price;

                $order = Order::query()
                    ->create([
                        'type'            => Order::TYPE_GOOD,
                        'shop_id'         => $shopId,
                        'user_id'         => $user->id,
                        'pay_no'          => $payNo,
                        'link_id'         => $goods->first()->id,
                        'title'           => $goods->first()->name,
                        'price'           => $price,
                        'original_price'  => $originalPrice,
                        'detail'          => $goodSpec->values(),
                        'coupon_pay'      => 0,
                        'discount_amount' => $discountAmount,
                        'status'          => Order::STATUS_INIT,
                        'referrer_id'     => $referrerId,
                        'referrer_level'  => is_null($referrerId) ? null : $referrer->level,
                        'mobile'          => $param['mobile'] ?? null,
                        'name'            => $param['name'] ?? null,
                        'address'         => $param['address'] ?? null,
                        'deliver_date'    => $param['deliver_date'] ?? null,
                        'cover'           => OSS::instance()->getUrl($goods->first()->order_cover),
                        'delivery'        => $param['delivery'] ?? 0,
                        'bill'            => $param['bill'] ?? null,
                        'personal_id'     => is_null($personal) ? null : $personal->id,
                        'final_payment'   => $isPrepay ? 0 : 1,
                        'is_prepay'       => $isPrepay,
                        'buyer_remark'    => isset($param['remark']) ? $param['remark'] : "",
                        'gift'            => $gift,
                        'is_recharge'     => $goods->first()->is_recharge, //是否是充值商品（买多少返多少）
                        'is_balance'      => $is_balance,
                        'balance_pay'     => $balance_pay,
                    ]);

//                if (!is_null($couponId)) {
//                    $coupon = UserCoupon::query()
//                        ->where('id', $couponId)
//                        ->where('shop_id', $shopId)
//                        ->where('user_id', $user->id)
//                        ->whereNull('use_id')
//                        ->where('expiration_date', ">=", Carbon::now()->toDateString())
//                        ->first();
//                    if (is_null($coupon)) {
//                        continue ;
//                    }
//                    if (!is_null($coupon->applicable)) {
//                        $limit = 0;
//                        foreach ($goodSpec as $item) {
//                            if (in_array($item['good_id'], $coupon->applicable)) {
//                                $limit += $item['price'] * $item['number'];
//                            }
//                        }
//                        if ($limit <= $coupon->limit) {
//                            throw new StandardException("无效优惠券");
//                        }
//                    }
//                    CouponManager::useCoupon($coupon, $order->id);
//                    $order->coupon_pay = $coupon->money;
//                    $order->save();
//                }
                $orders[] = $order;
            }

            $ids = [];
            $price = 0;
            $title = '';
            foreach ($orders as $unit) {
                $ids[] = $unit->id;
                $price += $unit->getPrice();
                $title = $unit->title;
            }

            // 非混合支付才可以返利
            $re = CombinedOrder::query()
                ->create([
                    'user_id'  => $user->id,
                    'title'    => $title,
                    'price'    => $price,
                    'pay_no'   => $payNo,
                    'order_id' => $ids,
                    'status'   => CombinedOrder::STATUS_INIT,
                ]);
            
            DB::commit();
            return $re;
        });
    }

    public static function getMiniProgramCode(User $user, $poster)
    {
        $miniProgram = EasyWeChat::miniProgram();
        $response = $miniProgram->app_code->getUnlimit($user->id . "#" . $poster->good_id . "#good", [
            'page' => "pages/product_detail/index",
            'width' => 136,
        ]);
        if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
            $key = "mini_program" . "/" . $user->id . "/" . $poster->good_id . ".png";

            // $dir = 'D:/_project/php/wedding/public/mini_program' . "/" . $user->id . "/";
            // if (!file_exists($dir)) {
            //     mkdir($dir, 0777, true);
            // }
            // $file_path = 'D:/_project/php/wedding/public/mini_program' . "/" . $user->id . "/" . $poster->good_id . ".png";
            // file_put_contents($file_path, $response->getBody()->getContents());

            /** @var OSS $oss */
            $oss = OSS::instance();
            $oss->storeBinary($key, $response->getBody()->getContents());
            return $key;
        } else {
            Log::error($response);
        }
        return null;
    }
}
